home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume22 / nn6.4 / part14 < prev    next >
Encoding:
Internet Message Format  |  1990-06-07  |  54.5 KB

  1. Subject:  v22i049:  NN Newsreader, release 6.4, Part14/21
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: a99df884 bc7915d1 6daa6fb5 f771e8c9
  5.  
  6. Submitted-by: "Kim F. Storm" <storm@texas.dk>
  7. Posting-number: Volume 22, Issue 49
  8. Archive-name: nn6.4/part14
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  answer.c conf/s-aix221.h macro.c nn.c
  17. # Wrapped by storm@texas.dk on Sun May  6 18:19:57 1990
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. echo If this archive is complete, you will see the following message:
  20. echo '          "shar: End of archive 14 (of 22)."'
  21. if test -f 'answer.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'answer.c'\"
  23. else
  24.   echo shar: Extracting \"'answer.c'\" \(18768 characters\)
  25.   sed "s/^X//" >'answer.c' <<'END_OF_FILE'
  26. X/*
  27. X *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  28. X *
  29. X *    Response handling.
  30. X */
  31. X
  32. X#include "config.h"
  33. X#include "news.h"
  34. X#include "term.h"
  35. X#include "keymap.h"
  36. X#include "options.h"
  37. X
  38. Xextern char *temp_file;
  39. X
  40. Xexport char *default_distribution = NULL;
  41. Xexport char *extra_mail_headers    = NULL;
  42. Xexport char *extra_news_headers    = NULL;
  43. Xexport char *mail_record    = NULL;
  44. Xexport char *news_record    = NULL;
  45. Xexport char *mail_script    = NULL;
  46. Xexport char *news_script    = NULL;
  47. Xexport char *mailer_program    = REC_MAIL;
  48. Xexport int  mailer_pipe_input    = 1;
  49. Xexport char *editor_program    = NULL;
  50. Xexport char *spell_checker    = NULL;
  51. X
  52. Xexport char *bug_address    = BUG_REPORT_ADDRESS;
  53. X
  54. Xexport int include_art_id    = 0;
  55. Xexport int include_full_header    = 0;
  56. Xexport int orig_to_include_mask    = 0x3;
  57. X
  58. Xexport int empty_answer_check    = 1; /* reject replies that are not edited */
  59. Xexport int response_check_pause = 0; /* time to wait for background cmds */
  60. Xexport char *response_dflt_answer = "send";
  61. X
  62. X#ifdef APPEND_SIGNATURE
  63. Xexport int append_sig_mail = 1; /* mail does not append it */
  64. X#else
  65. Xexport int append_sig_mail = 0;
  66. X#endif
  67. Xexport int append_sig_post = 0;    /* inews should always do this */
  68. Xexport int query_signature = 1;    /* query user */
  69. X
  70. X
  71. X#define INCL_MARK_SIZE    10
  72. X
  73. Xexport char included_mark[INCL_MARK_SIZE + 1] = ">";
  74. X
  75. Ximport char delayed_msg[];
  76. X
  77. Xstatic int ed_line;
  78. X
  79. X#ifdef NNTP
  80. X#ifdef NNTP_MINI_INEWS_HEADER
  81. X#include <time.h>
  82. X
  83. Xstatic mini_inews_header(t)
  84. XFILE *t;
  85. X{
  86. X    time_t now;
  87. X    extern struct tm *gmtime();
  88. X    extern char *asctime();
  89. X    char *date, host[64];
  90. X
  91. X    now = cur_time();
  92. X    date = asctime(gmtime(&now));
  93. X    date[3] = date[7] = date[10] = date[19] = date[24] = NUL;
  94. X    gethostname(host, 64);
  95. X
  96. X    fprintf(t, "Path: %s!%s\n", host, user_name());
  97. X    fprintf(t, "Date: %s %s %s %s GMT\n", date+8, date+4, date+22, date+11);
  98. X    fprintf(t, "Message-ID: <%s.%ld@%s>\n", user_name, (long)now, host);
  99. X    ed_line += 3;
  100. X}
  101. X#endif
  102. X#endif
  103. X
  104. Xstatic subj_line(t, re, subj, prefix)
  105. XFILE *t;
  106. Xint re;
  107. Xchar *subj, *prefix;
  108. X{
  109. X    if (subj == NULL) return 0;
  110. X
  111. X    fputs("Subject: ", t);
  112. X
  113. X    if (re >= 0)
  114. X    fputs("Re: ", t);
  115. X
  116. X    if (prefix) {
  117. X    fputs(prefix, t);
  118. X    fputc(' ', t);
  119. X    }
  120. X
  121. X    fputs(subj, t);
  122. X    fputc(NL, t);
  123. X
  124. X    ed_line++;
  125. X    return 1;
  126. X}
  127. X
  128. X
  129. Xstatic ng_line(t, use_follow)
  130. XFILE *t;
  131. Xint use_follow;
  132. X{
  133. X    fprintf(t, "Newsgroups: %s\n",
  134. X        use_follow && news.ng_follow ? news.ng_follow : news.ng_groups);
  135. X    ed_line++;
  136. X}
  137. X
  138. Xstatic ref_line(t)
  139. XFILE *t;
  140. X{
  141. X    if (news.ng_ref == NULL && news.ng_ident == NULL) return;
  142. X
  143. X    fputs("References:", t);
  144. X    if (news.ng_ref) fprintf(t, " %s", news.ng_ref);
  145. X    if (news.ng_ident) fprintf(t, " %s", news.ng_ident);
  146. X    putc(NL, t);
  147. X    ed_line++;
  148. X}
  149. X
  150. X
  151. Xstatic to_line(t, to)
  152. XFILE *t;
  153. Xchar *to;
  154. X{
  155. X    if (to == NULL) return 0;
  156. X
  157. X    fprintf(t, "To: %s\n", to);
  158. X    ed_line++;
  159. X    return 1;
  160. X}
  161. X
  162. Xstatic alt_to_line(t, to, mask)
  163. XFILE *t;
  164. Xchar *to;
  165. Xint mask;
  166. X{
  167. X    if (to == NULL) return;
  168. X    if (mask && (orig_to_include_mask & mask) == 0) return;
  169. X
  170. X    fprintf(t, "Orig-To: %s\n", to);
  171. X    ed_line++;
  172. X}
  173. X
  174. Xstatic end_header(t, extra_headers)
  175. XFILE *t;
  176. Xregister char *extra_headers;
  177. X{
  178. X    if (extra_headers != NULL && *extra_headers != NUL) {
  179. X    while (*extra_headers != NUL) {
  180. X        if (*extra_headers == ';') {
  181. X        if (*++extra_headers == NUL) break;
  182. X        fputc(NL, t);
  183. X        ed_line++;
  184. X        } else
  185. X        fputc(*extra_headers++, t);
  186. X    }
  187. X    fputc(NL, t);
  188. X    ed_line++;
  189. X    }
  190. X
  191. X    fputc(NL, t);
  192. X    ed_line++;
  193. X}
  194. X
  195. X
  196. Xstatic reply_to(t, address)
  197. XFILE *t;
  198. Xchar *address;
  199. X{
  200. X    char route[512];
  201. X
  202. X    if (address == NULL) return 0;
  203. X
  204. X    if (reroute(route, address)) {
  205. X    to_line(t, route);
  206. X    return 1;
  207. X    }
  208. X    return 0;
  209. X}
  210. X
  211. X
  212. X/*
  213. X * invoke aux shell script with suitable arguments
  214. X *
  215. X * WARNING: record may be NULL, so it must be the last argument!!
  216. X */
  217. X
  218. Xstatic aux_param_bool(f, name, on)
  219. XFILE *f;
  220. Xchar *name;
  221. Xint on;
  222. X{
  223. X    fprintf(f, "%s=%s\n", name, on ? "true" : "false");
  224. X}
  225. X
  226. Xstatic aux_param_str(f, name, str)
  227. XFILE *f;
  228. Xchar *name, *str;
  229. X{
  230. X    fprintf(f, "%s='%s'\n", name, str != NULL ? str : "");
  231. X}
  232. X
  233. Xstatic aux_param_int(f, name, i)
  234. XFILE *f;
  235. Xchar *name;
  236. Xint i;
  237. X{
  238. X    fprintf(f, "%s=%d\n", name, i);
  239. X}
  240. X
  241. Xstatic aux_sh(ah, script, prog, action, record, sent_fmt, append_sig)
  242. Xarticle_header *ah;
  243. Xchar *script, *prog, *action, *record, *sent_fmt;
  244. Xint append_sig;
  245. X{
  246. X    FILE *param;
  247. X    char *args[10], *fn;
  248. X    register char **ap = args;
  249. X    import int novice;
  250. X    import char *pager;
  251. X#ifdef NNTP
  252. X    extern char *nntp_get_filename();
  253. X#endif
  254. X
  255. X    param = open_file(relative(nn_directory, ".param"), OPEN_CREATE);
  256. X    if (param == NULL) {
  257. X    strcpy(delayed_msg, "cannot create .param file for aux script");
  258. X    return 0;
  259. X    }
  260. X
  261. X    if (strcmp(prog, "cancel") == 0) {
  262. X    aux_param_str(param, "ART_ID", action);    /* article id for cancel */
  263. X    aux_param_str(param, "GROUP", record);    /* group name for cancel */
  264. X    } else {
  265. X    aux_param_str(param, "FIRST_ACTION", action);
  266. X    aux_param_str(param, "RECORD", record);
  267. X    aux_param_str(param, "WORK", temp_file);
  268. X    aux_param_int(param, "ED_LINE", ed_line);
  269. X
  270. X    aux_param_bool(param, "NOVICE", novice);
  271. X    aux_param_bool(param, "EMPTY_CHECK", empty_answer_check);
  272. X    aux_param_bool(param, "APPEND_SIG", append_sig);
  273. X    aux_param_bool(param, "QUERY_SIG", append_sig && query_signature);
  274. X
  275. X    if (editor_program != NULL)
  276. X        aux_param_str(param, "EDITOR", editor_program);
  277. X    aux_param_str(param, "SPELL_CHECKER", spell_checker);
  278. X    aux_param_str(param, "PAGER", pager);
  279. X    aux_param_str(param, "MAILER", mailer_program);
  280. X    aux_param_bool(param, "MAILER_PIPE", mailer_pipe_input);
  281. X    aux_param_int(param, "WAIT_PERIOD", response_check_pause);
  282. X    aux_param_str(param, "DFLT_ANSW", response_dflt_answer);
  283. X
  284. X    if (current_group != NULL) {
  285. X        aux_param_str(param, "G", current_group->group_name);
  286. X        if (ah == NULL)
  287. X        fn = NULL;
  288. X        else
  289. X#ifdef NNTP
  290. X        if (use_nntp)
  291. X        fn = nntp_get_filename(ah->a_number, current_group);
  292. X        else
  293. X#endif
  294. X        fn = group_path_name;
  295. X        aux_param_str(param, "A", fn != NULL ? fn : "");
  296. X    }
  297. X
  298. X    /*
  299. X    aux_param_str(param, "", );
  300. X    aux_param_bool(param, "", );
  301. X    aux_param_int(param, "", );
  302. X    */
  303. X    }
  304. X
  305. X    fclose(param);
  306. X
  307. X    stop_usage();
  308. X
  309. X    /* OBS: relative() returns ptr to static data below */
  310. X    *ap++ = "nnaux";
  311. X    *ap++ = script != NULL ? script : relative(lib_directory, "aux");
  312. X    *ap++ = prog;
  313. X    *ap++ = NULL;
  314. X
  315. X    if (execute(SHELL, args, 1)) {
  316. X    sprintf(delayed_msg, sent_fmt, " not");
  317. X    return 1;
  318. X    }
  319. X    sprintf(delayed_msg, sent_fmt, "");
  320. X    return 0;
  321. X}
  322. X
  323. Xstatic append_file(name, f)
  324. Xchar *name;
  325. Xregister FILE *f;
  326. X{
  327. X    register FILE *s;
  328. X    register int c;
  329. X    
  330. X    s = open_file(name, OPEN_READ);
  331. X    if (s == NULL) return;
  332. X    
  333. X    while ((c = getc(s)) != EOF) putc(c, f);
  334. X    fclose(s);
  335. X}
  336. X
  337. Xanswer(ah, command, incl)
  338. Xarticle_header *ah;
  339. Xint command;
  340. Xint incl;    /* <0: ask, 0: don't include, >0: include article */
  341. X{
  342. X    register FILE *t, *art;
  343. X    char *pgm, *first_action, *record_file;
  344. X    int edit_message, append_sig;
  345. X    char *str, *script;
  346. X    news_header_buffer nhbuf, dhbuf;
  347. X
  348. X    first_action = "edit";
  349. X    edit_message = 1;
  350. X    append_sig = 0;
  351. X
  352. X    if (incl < 0) {
  353. X    prompt("Include original article? ");
  354. X    if ((incl = yes(0)) < 0) return 0;
  355. X    }
  356. X
  357. X    art = NULL;
  358. X    if (ah && ah->a_group) init_group(ah->a_group);
  359. X
  360. X    if (incl || (command != K_MAIL_OR_FORWARD && command != K_BUG_REPORT)) {
  361. X    int open_modes;
  362. X
  363. X    open_modes = FILL_NEWS_HEADER | GET_ALL_FIELDS | SKIP_HEADER;
  364. X    if (ah->flag & A_DIGEST) open_modes |= FILL_DIGEST_HEADER;
  365. X
  366. X    art = open_news_article(ah, open_modes, nhbuf, dhbuf);
  367. X    if (art == NULL) {
  368. X        msg("Can't find original article");
  369. X        return 0;
  370. X    }
  371. X
  372. X    if (ah->flag & A_DIGEST) {
  373. X        if (digest.dg_from)
  374. X        news.ng_path = news.ng_from = digest.dg_from;
  375. X        if (digest.dg_subj)
  376. X        news.ng_subj = digest.dg_subj;
  377. X    }
  378. X    } else
  379. X    ah = NULL;
  380. X
  381. X    /* build header */
  382. X    new_temp_file();
  383. X
  384. X    if ((t = open_file(temp_file, OPEN_CREATE)) == NULL) {
  385. X    msg("Can't create %s", temp_file);
  386. X    return 0;
  387. X    }
  388. X
  389. X    ed_line = 0;
  390. X
  391. X follow_to_poster:
  392. X
  393. X    record_file = mail_record;
  394. X    script = mail_script;
  395. X
  396. X    if (command == K_REPLY) {
  397. X    pgm = "reply";
  398. X    append_sig = append_sig_mail;
  399. X
  400. X    ah->flag |= A_ST_REPLY;
  401. X
  402. X    if (reply_to(t, news.ng_reply) ||
  403. X        reply_to(t, news.ng_from) ||
  404. X        reply_to(t, news.ng_path)) goto alt0;
  405. X    if (to_line(t, news.ng_reply)) goto alt1;
  406. X    if (to_line(t, news.ng_from)) goto alt2;
  407. X    if (to_line(t, news.ng_path)) goto alt3;
  408. X    goto err;
  409. X
  410. X     alt0:
  411. X    alt_to_line(t, news.ng_reply, 0x1);
  412. X     alt1:
  413. X    alt_to_line(t, news.ng_from, 0x2);
  414. X     alt2:
  415. X    alt_to_line(t, news.ng_path, 0x4);
  416. X     alt3:
  417. X
  418. X    if (news.ng_subj)
  419. X        subj_line(t, ah->replies, ah->subject, (char *)NULL);
  420. X    else
  421. X        subj_line(t, 0, current_group->group_name, "Your Article in");
  422. X
  423. X    ng_line(t, 0);
  424. X    ref_line(t);
  425. X
  426. X    end_header(t, extra_mail_headers);
  427. X
  428. X    if (incl) {
  429. X        fprintf(t, "In %s you write:\n", current_group->group_name);
  430. X        ed_line++;
  431. X    }
  432. X    }
  433. X
  434. X    if (command == K_FOLLOW_UP) {
  435. X    if (news.ng_follow && strcmp(news.ng_follow, "poster") == 0) {
  436. X        command = K_REPLY;
  437. X        msg("Followup by reply to poster");
  438. X        goto follow_to_poster;
  439. X    }
  440. X
  441. X    pgm = "follow";
  442. X    record_file = news_record;
  443. X    script = news_script;
  444. X    append_sig = append_sig_post;
  445. X
  446. X    ah->flag |= A_ST_FOLLOW;
  447. X
  448. X#ifdef NNTP
  449. X#ifdef NNTP_MINI_INEWS_HEADER
  450. X    mini_inews_header(t);
  451. X#endif
  452. X#endif
  453. X    ng_line(t, 1);
  454. X
  455. X    if (news.ng_subj)
  456. X        subj_line(t, ah->replies, ah->subject, (char *)NULL);
  457. X    else
  458. X        if (!subj_line(t, 0, news.ng_from, "Babble from"))
  459. X        if (!subj_line(t, 0, news.ng_ident, "Article")) {
  460. X            prompt("Subject: ");
  461. X            str = get_s(NONE, NONE, NONE, NULL_FCT);
  462. X            if (str == NULL) goto err;
  463. X            subj_line(t, -1, str, (char *)NULL);
  464. X        }
  465. X
  466. X    if (news.ng_keyw) {
  467. X        fprintf(t, "Keywords: %s\n", news.ng_keyw);
  468. X        ed_line++;
  469. X    }
  470. X
  471. X    if (news.ng_dist) {
  472. X        fprintf(t, "Distribution: %s\n", news.ng_dist);
  473. X        ed_line++;
  474. X    }
  475. X
  476. X    ref_line(t);
  477. X
  478. X    end_header(t, extra_news_headers);
  479. X
  480. X    if (incl) {
  481. X        if (news.ng_from) {
  482. X        if (include_art_id && news.ng_ident)
  483. X            fprintf(t, "In%s %s ",
  484. X                ah->flag & A_DIGEST ? " digest" : "",
  485. X                news.ng_ident);
  486. X        fprintf(t, "%s writes:\n", news.ng_from);
  487. X        ed_line++;
  488. X        } else
  489. X        if (news.ng_ident) {
  490. X        fprintf(t, "In %s %s:\n",
  491. X            ah->flag & A_DIGEST ? "digest" : "article",
  492. X            news.ng_ident);
  493. X        ed_line++;
  494. X        }
  495. X    }
  496. X    }
  497. X
  498. X    if (command == K_MAIL_OR_FORWARD || command == K_BUG_REPORT) {
  499. X    pgm = incl ? "forward" : "mail";
  500. X    append_sig = append_sig_mail;
  501. X
  502. X     m3_again:
  503. X    prompt("To: ");
  504. X    str = get_s(user_name(),
  505. X            command == K_BUG_REPORT ? bug_address : NONE,
  506. X            NONE, NULL_FCT);
  507. X    if (str == NULL) goto close_t;
  508. X
  509. X    if (*str == NUL) str = user_name();
  510. X    if (*str == '?') goto m3_again;
  511. X
  512. X    if (strcmp(str, user_name()) == 0)
  513. X        record_file = NULL;    /* we will get this anyway,
  514. X                   there is so no need to save it */
  515. X
  516. X/*    if (reply_to(t, str)) {        alt_to_line(t, str, 0);    } else */
  517. X    to_line(t, str);
  518. X
  519. X    do {
  520. X        prompt("Subject: ");
  521. X        str = get_s(incl ? ah->subject : NONE,
  522. X            command == K_BUG_REPORT ? "nn bug report" : NONE,
  523. X            NONE, NULL_FCT);
  524. X        if (str == NULL) goto close_t;
  525. X        if (*str == NUL && incl) str = ah->subject;
  526. X    } while (*str == NUL);
  527. X
  528. X    subj_line(t, -1, str, (char *)NULL);
  529. X
  530. X    end_header(t, extra_mail_headers);
  531. X
  532. X    if (incl) {
  533. X        prompt("\1Edit\1 forwarded message? ");
  534. X        if ((edit_message = yes(0)) < 0) goto close_t;
  535. X        if (!edit_message) {
  536. X        first_action = "send";
  537. X        fseek(art, ah->hpos, 0);
  538. X        } else
  539. X        if (include_full_header && command == K_MAIL_OR_FORWARD)
  540. X            fseek(art, ah->hpos, 0);
  541. X    }
  542. X
  543. X    if (command == K_BUG_REPORT) {
  544. X        fprintf(t, "\n=== configuration ===\n");
  545. X        append_file(relative(lib_directory, "conf"), t);
  546. X        fprintf(t, "=== end ===\n");
  547. X    }
  548. X    }
  549. X
  550. X    /* empty line terminates header */
  551. X    fputc(NL, t);
  552. X    ed_line++;
  553. X
  554. X    prompt("\1WAIT\1");
  555. X
  556. X    if (incl) {
  557. X    register c, prevnl = 1;
  558. X
  559. X    while ((c = getc(art)) != EOF) {
  560. X        if (c == NL) {
  561. X        putc(c, t);
  562. X        if (ftell(art) >= ah->lpos) break;
  563. X        prevnl++;
  564. X        continue;
  565. X        }
  566. X        if (prevnl) {
  567. X        if (command != K_MAIL_OR_FORWARD || ftell(art) < ah->fpos)
  568. X            fputs(included_mark, t);
  569. X        prevnl = 0;
  570. X        }
  571. X        putc(c, t);
  572. X    }
  573. X    } else {
  574. X    putc(NL, t);
  575. X    ed_line++;
  576. X    }
  577. X
  578. X    fclose(t);
  579. X    if (art) fclose(art);
  580. X
  581. X    aux_sh(ah, script, pgm, first_action, record_file,
  582. X       command == K_FOLLOW_UP ? "Article%s posted" : "Mail%s sent",
  583. X       append_sig);
  584. X
  585. X    return edit_message;
  586. X
  587. X err:
  588. X    msg("Can't build header for %s",
  589. X    command != K_FOLLOW_UP ? "letter" : "article");
  590. X
  591. X close_t:
  592. X    fclose(t);
  593. X    unlink(temp_file);
  594. X    if (art) fclose(art);
  595. X
  596. X    return 0;
  597. X}
  598. X
  599. X
  600. X/*
  601. X *    inet_name: return "<user_name()>@<host_name()>"
  602. X */
  603. X
  604. Xstatic char *inet_name()
  605. X{
  606. X    static char *inetname = NULL;
  607. X    char hname[100], *un;
  608. X
  609. X    if (inetname == NULL) {
  610. X    gethostname(hname, 100);
  611. X    un = user_name();
  612. X    inetname = newstr(strlen(hname) + strlen(un) + 2);
  613. X    sprintf(inetname, "%s@%s", un, hname);
  614. X    }
  615. X    return inetname;
  616. X}
  617. X
  618. X/*
  619. X *  check_sender: If sender is "root", "news", the full name or the internet
  620. X *  name of the user, return 1 otherwise 0
  621. X */
  622. X
  623. Xstatic int check_sender(sender)
  624. Xchar *sender;
  625. X{
  626. X    char *full_name();
  627. X
  628. X    return strcmp(user_name(), "root") == 0
  629. X    || strcmp(user_name(), "news") == 0
  630. X    || strmatch(full_name(), sender)
  631. X    || strmatch(inet_name(), sender);
  632. X}
  633. X
  634. X
  635. Xcancel(ah)
  636. Xarticle_header *ah;
  637. X{
  638. X    news_header_buffer nhbuf;
  639. X    FILE *f;
  640. X
  641. X    if (ah->a_group) init_group(ah->a_group);
  642. X
  643. X    if (ah->flag & A_DIGEST) {
  644. X    fputs("\rCancel entire digest ? ", stdout); clrline();
  645. X    if (yes(1) > 0)
  646. X        ah->flag &= ~A_DIGEST;
  647. X    else {
  648. X        msg("Can only cancel entire digests (yet?)");
  649. X        return 2;
  650. X    }
  651. X    }
  652. X
  653. X    f = open_news_article(ah, FILL_NEWS_HEADER|GET_ALL_FIELDS, nhbuf, (char *)NULL);
  654. X    if (f == NULL) {
  655. X    msg("Article not found");
  656. X    return 2;
  657. X    }
  658. X    fclose(f);
  659. X
  660. X    if  (! check_sender(news.ng_from)) {
  661. X    msg("You can only cancel your own articles!");
  662. X    return 1;
  663. X    }
  664. X
  665. X    prompt("Confirm cancel: '%s: %.30s'",
  666. X       ah->sender ? ah->sender : "",
  667. X       ah->subject ? ah->subject : "");
  668. X    if (yes(1) <= 0) return 1;
  669. X
  670. X    printf("\rCancelling article %s in group %s",
  671. X       news.ng_ident, current_group->group_name);
  672. X    clrline();
  673. X
  674. X    ed_line = -1;
  675. X
  676. X    if (aux_sh(ah, (char *)NULL, "cancel", news.ng_ident, current_group->group_name,
  677. X           "Article%s cancelled", 0))
  678. X    return -1;
  679. X
  680. X    return 0;
  681. X}
  682. X
  683. Xstatic char *post_distribution = NULL;
  684. Xstatic char *post_subject = NULL;
  685. Xstatic char *post_summary = NULL;
  686. Xstatic char *post_keywords = NULL;
  687. Xstatic char *post_source_file = NULL;
  688. Xstatic int post_no_edit = 0;
  689. Xstatic char *post_to_groups = NULL;
  690. X
  691. XOption_Description(post_options) {
  692. X    'd', String_Option(post_distribution),
  693. X    'f', String_Option(post_source_file),
  694. X    'k', String_Option(post_keywords),
  695. X    's', String_Option(post_subject),
  696. X    'y', String_Option(post_summary),
  697. X    'p', Bool_Option(post_no_edit),
  698. X    '\0',
  699. X};
  700. X
  701. Xdo_nnpost(argc, argv)
  702. Xint argc;
  703. Xchar *argv[];
  704. X{
  705. X    int ngroups, i;
  706. X    char newsgroups[FILENAME*2];
  707. X
  708. X    init_term();
  709. X    visit_init_file(0, (char *)NULL);
  710. X    current_group = NULL;
  711. X
  712. X    ngroups =
  713. X    parse_options(argc, argv, (char *)NULL, post_options,
  714. X              " newsgroup...");
  715. X
  716. X    if (post_no_edit && post_source_file == NULL) {
  717. X    printf("Must specify a source file with -p\n");
  718. X    nn_exit(1);
  719. X    }
  720. X
  721. X    if (ngroups > 0) {
  722. X    strcpy(newsgroups, argv[1]);
  723. X    for (i = 2; i <= ngroups; i++) {
  724. X        strcat(newsgroups, ",");
  725. X        strcat(newsgroups, argv[i]);
  726. X    }
  727. X    post_to_groups = newsgroups;
  728. X    }
  729. X
  730. X    raw();
  731. X    clrdisp();
  732. X    prompt_line = 0;
  733. X    post_menu();
  734. X    putchar(CR); putchar(NL);
  735. X    unset_raw();
  736. X    if (*delayed_msg)
  737. X    printf("%s\n", delayed_msg);
  738. X
  739. X    nn_exit(0);
  740. X}
  741. X
  742. Xpost_menu()
  743. X{
  744. X    register FILE *t, *src;
  745. X    register int c;
  746. X    char *str, *tail;
  747. X    char group_name[FILENAME], subject[FILENAME],
  748. X     distribution[FILENAME], keywords[FILENAME], summary[FILENAME];
  749. X    extern group_completion();
  750. X
  751. X    if (post_source_file) {
  752. X    src = open_file(post_source_file, OPEN_READ);
  753. X    if (src == NULL) {
  754. X        printf("File %s not found\n");
  755. X        nn_exit(1);
  756. X    }
  757. X    }
  758. X
  759. X    if (post_to_groups)
  760. X    strcpy(group_name, post_to_groups);
  761. X    else {
  762. X    group_name[0] = NUL;
  763. X
  764. X     again_group:
  765. X
  766. X    prompt(who_am_i == I_AM_POST ? "Newsgroups: " : "\1POST to group\1 ");
  767. X
  768. X    str = get_s(current_group ? current_group->group_name : NONE,
  769. X            group_name, NONE, group_completion);
  770. X    if (str == NULL) return 0;
  771. X    if (*str == NUL) {
  772. X        if (current_group == NULL || (current_group->group_flag & G_FAKED))
  773. X        return 0;
  774. X        str = current_group->group_name;
  775. X    }
  776. X    strcpy(group_name, str);
  777. X
  778. X    for (str = group_name; str; str = tail) {
  779. X        tail = strchr(str, ',');
  780. X        if (tail) *tail = NUL;
  781. X
  782. X        if (lookup(str) == NULL) {
  783. X        msg("unknown group: %s", str);
  784. X        *str = NUL;
  785. X        goto again_group;
  786. X        }
  787. X
  788. X        if (tail) *tail++ = ',';
  789. X    }
  790. X    if (who_am_i == I_AM_POST) prompt_line++;
  791. X    }
  792. X
  793. X    if ((str = post_subject) == NULL) {
  794. X    prompt("Subject: ");
  795. X    str = get_s(NONE, NONE, NONE, NULL_FCT);
  796. X    if (str == NULL || *str == NUL) return 0;
  797. X    if (who_am_i == I_AM_POST) prompt_line++;
  798. X    }
  799. X    strcpy(subject, str);
  800. X
  801. X    if ((str = post_keywords) == NULL) {
  802. X    prompt("Keywords: ");
  803. X    str = get_s(NONE, NONE, NONE, NULL_FCT);
  804. X    if (str == NULL) return 0;
  805. X    if (who_am_i == I_AM_POST) prompt_line++;
  806. X    }
  807. X    strcpy(keywords, str);
  808. X
  809. X    if ((str = post_summary) == NULL) {
  810. X    prompt("Summary: ");
  811. X    str = get_s(NONE, NONE, NONE, NULL_FCT);
  812. X    if (str == NULL) return 0;
  813. X    if (who_am_i == I_AM_POST) prompt_line++;
  814. X    }
  815. X    strcpy(summary, str);
  816. X
  817. X    if (post_distribution) {
  818. X    strcpy(distribution, post_distribution);
  819. X    } else {
  820. X    if (default_distribution != NULL)
  821. X        strcpy(distribution, default_distribution);
  822. X    else {
  823. X        strcpy(distribution, group_name);
  824. X        if (str = strchr(distribution, ',')) *str = NUL;
  825. X        if (str = strchr(distribution, '.')) *str = NUL;
  826. X    }
  827. X
  828. X    prompt("Distribution: (default '%s') ", distribution);
  829. X    str = get_s(NONE, NONE, NONE, NULL_FCT);
  830. X    if (str == NULL) return 0;
  831. X    if (*str) strcpy(distribution, str);
  832. X    if (who_am_i == I_AM_POST) prompt_line++;
  833. X    }
  834. X
  835. X    new_temp_file();
  836. X    if ((t = open_file(temp_file, OPEN_CREATE)) == NULL) {
  837. X    msg("Can't create %s", temp_file);
  838. X    return 0;
  839. X    }
  840. X
  841. X    if (!post_no_edit)
  842. X    prompt("\1WAIT\1");
  843. X
  844. X    ed_line = 3;
  845. X#ifdef NNTP
  846. X#ifdef NNTP_MINI_INEWS_HEADER
  847. X    mini_inews_header(t);
  848. X#endif
  849. X#endif
  850. X    fprintf(t, "Newsgroups: %s\n", group_name);
  851. X    fprintf(t, "Distribution: %s\n", distribution);
  852. X    fprintf(t, "Subject: %s\n", subject);
  853. X    if (*summary) {
  854. X    fprintf(t, "Summary: %s\n", summary);
  855. X    ed_line++;
  856. X    }
  857. X    if (*keywords) {
  858. X    fprintf(t, "Keywords: %s\n", keywords);
  859. X    ed_line++;
  860. X    }
  861. X
  862. X    end_header(t, extra_news_headers);
  863. X
  864. X    if (post_source_file) {
  865. X    while ((c = getc(src)) != EOF) putc(c, t);
  866. X    fclose(src);
  867. X    } else
  868. X    fputc(NL, t);
  869. X
  870. X    fclose(t);
  871. X
  872. X    aux_sh((article_header *)NULL, news_script, "post",
  873. X       post_no_edit ? "send" : "edit", news_record,
  874. X       "Article%s posted", append_sig_post);
  875. X
  876. X    return 1;
  877. X}
  878. X
  879. END_OF_FILE
  880.   if test 18768 -ne `wc -c <'answer.c'`; then
  881.     echo shar: \"'answer.c'\" unpacked with wrong size!
  882.   fi
  883.   # end of 'answer.c'
  884. fi
  885. if test -f 'conf/s-aix221.h' -a "${1}" != "-c" ; then 
  886.   echo shar: Will not clobber existing file \"'conf/s-aix221.h'\"
  887. else
  888.   echo shar: Extracting \"'conf/s-aix221.h'\" \(447 characters\)
  889.   sed "s/^X//" >'conf/s-aix221.h' <<'END_OF_FILE'
  890. X/*
  891. X *    This version is for AIX 2.2.1
  892. X *    From: marcel@duteca.tudelft.nl (Marcel J.E. Mol)
  893. X */
  894. X
  895. X/*
  896. X *    Notice: AIX's PRINTER command is "print"  (see config.h)
  897. X */
  898. X
  899. X#include <s-sys5.h>
  900. X
  901. X/*
  902. X *    AIX does have void signal handlers, but
  903. X *    a   typedef void   does not work
  904. X */
  905. X
  906. X#undef    SIGNAL_HANDLERS_ARE_VOID
  907. X
  908. X/*
  909. X *    Define HAVE_GETHOSTNAME if your system provides a BSD like
  910. X *    gethostname routine.
  911. X */
  912. X
  913. X#undef  HAVE_UNAME
  914. X#define    HAVE_GETHOSTNAME
  915. X
  916. END_OF_FILE
  917.   if test 447 -ne `wc -c <'conf/s-aix221.h'`; then
  918.     echo shar: \"'conf/s-aix221.h'\" unpacked with wrong size!
  919.   fi
  920.   # end of 'conf/s-aix221.h'
  921. fi
  922. if test -f 'macro.c' -a "${1}" != "-c" ; then 
  923.   echo shar: Will not clobber existing file \"'macro.c'\"
  924. else
  925.   echo shar: Extracting \"'macro.c'\" \(14186 characters\)
  926.   sed "s/^X//" >'macro.c' <<'END_OF_FILE'
  927. X/*
  928. X *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  929. X *
  930. X *    Macro parsing and execution.
  931. X */
  932. X
  933. X#include "config.h"
  934. X#include "keymap.h"
  935. X#include "term.h"
  936. X
  937. Xexport int in_menu_mode = 0;
  938. Xexport int get_from_macro = 0;
  939. Xexport int macro_debug = 0;
  940. Xexport char *dflt_enter_macro = NULL;
  941. X
  942. X#define M_DUMMY        0    /* do nothing (end of branch)     */
  943. X
  944. X#define    M_COMMAND    1    /* a command (get_c())          */
  945. X#define M_KEY        2    /* a key stroke (get_c())      */
  946. X#define M_STRING    3    /* a string (get_s())         */
  947. X
  948. X#define M_INPUT        4    /* take input from keyboard (get_c/get_s) */
  949. X
  950. X#define M_YES        5    /* answer yes to confirmation     */
  951. X#define M_NO        6    /* answer no to confirmation and break */
  952. X                /* -- if neither are present, take input */
  953. X
  954. X#define M_PUTS        7    /* puts "..."             */
  955. X#define M_PROMPT    8    /* prompt(...)              */
  956. X#define M_ECHO        9    /* msg(...)             */
  957. X
  958. X#define M_IS_MENU    10    /* in menu mode ?         */
  959. X#define M_IS_SHOW    11    /* in reading mode ?         */
  960. X#define M_IS_GROUP    12    /* are we in a news group ?     */
  961. X#define M_IS_FOLDER    13    /* are we in a folder ?         */
  962. X#define M_CONFIRM    14    /* ask for confirmation to procede     */
  963. X#define M_REJECT    15    /* ask for !confirmation to procede     */
  964. X#define M_VARTEST    16    /* test value of variable     */
  965. X#define M_BREAK        17    /* exit from macroes         */
  966. X#define    M_RETURN    18    /* return from this macro     */
  967. X
  968. X#define    M_SET_COMMAND    19    /* set/unset command         */
  969. X
  970. X
  971. Xstruct macro {
  972. X    int            m_type;        /* entry type */
  973. X    union {
  974. X    int         mu_int;        /* command or char */
  975. X    char         *mu_string;    /* string for get_s */
  976. X    struct macro     *mu_branch;    /* false conditional */
  977. X    } m_value;
  978. X    struct macro *m_next;        /* next macro element */
  979. X};
  980. X
  981. X#define m_int        m_value.mu_int
  982. X#define m_string    m_value.mu_string
  983. X#define m_branch    m_value.mu_branch
  984. X
  985. X#define NUM_MACRO 101        /* numbered macros */
  986. X#define ANON_MACRO 100        /* anonymous macroes */
  987. X#define NMACRO (NUM_MACRO + ANON_MACRO)
  988. X
  989. X#define MSTACK 5        /* max nesting level */
  990. X
  991. Xstatic struct macro *macro[NMACRO + 1];     /* macro table */
  992. X                /* the extra slot is for entry macroes */
  993. X
  994. Xstatic struct macro *mstack[MSTACK];    /* macro stack */
  995. Xstatic int cstack[MSTACK + 1];
  996. Xstatic int m_level = 0;
  997. X
  998. Xstatic struct macro *m = NULL;        /* current macro */
  999. Xstatic int no_advance = 0;
  1000. Xstatic int changed_prompt = 0;
  1001. X
  1002. Xstatic int cur_m;
  1003. X
  1004. X#define MERROR ((struct macro *)1)
  1005. X
  1006. Xstatic m_error(fmt, arg)
  1007. Xchar *fmt, *arg;
  1008. X{
  1009. X    char buf[80];
  1010. X
  1011. X   if (arg) {
  1012. X       sprintf(buf, fmt, arg);
  1013. X       fmt = buf;
  1014. X   }
  1015. X
  1016. X   init_message("Error in macro %d: %s", cur_m, fmt);
  1017. X}
  1018. X
  1019. Xinit_macro()
  1020. X{
  1021. X    int n;
  1022. X
  1023. X    for (n = 0; n <= NMACRO; n++)
  1024. X    macro[n] = NULL;
  1025. X}
  1026. X
  1027. Xstatic m_new(t)
  1028. Xint t;
  1029. X{
  1030. X    struct macro *m1;
  1031. X
  1032. X    m1 = newobj(struct macro, 1);
  1033. X
  1034. X    if (m == NULL)
  1035. X    m = macro[cur_m] = m1;
  1036. X    else {
  1037. X    m->m_next = m1;
  1038. X    m = m1;
  1039. X    }
  1040. X    m->m_type = t;
  1041. X    m->m_next = NULL;
  1042. X}
  1043. X
  1044. X
  1045. X/*
  1046. X *    Define macro "id" reading from file f until "end"
  1047. X *
  1048. X *    Macro definition syntax:
  1049. X *        define <id>
  1050. X *           <body>
  1051. X *        end
  1052. X *
  1053. X *    Id string interpretation:
  1054. X *    NULL         use next free numbered macro
  1055. X *            Return: pointer to macro
  1056. X *    "nnn" nnn>=0    Numbered macro nnn
  1057. X *            Return: pointer to macro
  1058. X *    "-1"        entry macro
  1059. X *            Return: pointer to macro
  1060. X *    "-2"        anonymous macro
  1061. X *            Return: K_MACRO code or K_UNBOUND on error
  1062. X */
  1063. X
  1064. Xstatic int initial_set_commands;
  1065. X
  1066. Xstatic parse_word(w)
  1067. Xchar *w;
  1068. X{
  1069. X    int cmd;
  1070. X    register struct macro *m1;
  1071. X
  1072. X    if (m && m->m_type == M_COMMAND && m->m_int == (GETC_COMMAND | K_MACRO)) {
  1073. X    if (isdigit(*w)) {
  1074. X        m->m_int |= atoi(w);
  1075. X        goto ok;
  1076. X    }
  1077. X    m_error("macro number missing", (char *)NULL);
  1078. X    return 1;
  1079. X    }
  1080. X
  1081. X    if (*w == '"') {
  1082. X    if (m == NULL || (m->m_type != M_PROMPT && m->m_type != M_ECHO && m->m_type != M_PUTS))
  1083. X        m_new(M_STRING);
  1084. X    m->m_string = copy_str(w + 1);
  1085. X    goto ok;
  1086. X    }
  1087. X
  1088. X    if (*w == '\'') {
  1089. X    m_new(M_KEY);
  1090. X    m->m_int = parse_key(w + 1);
  1091. X    goto ok;
  1092. X    }
  1093. X
  1094. X    if (*w == '?') {
  1095. X    if (strchr(w, '=')) {
  1096. X        m->m_type = M_VARTEST;
  1097. X        m1 = m;
  1098. X        m_new(M_DUMMY);
  1099. X        m->m_branch = m1->m_branch;
  1100. X        m1->m_string = copy_str(w + 1);
  1101. X        goto ok;
  1102. X    }
  1103. X
  1104. X    switch (w[1]) {
  1105. X     case 'f': /* ?folder */
  1106. X        cmd = M_IS_FOLDER;
  1107. X        break;
  1108. X     case 'g': /* ?group */
  1109. X        cmd = M_IS_GROUP;
  1110. X        break;
  1111. X     case 'm': /* ?menu */
  1112. X        cmd = M_IS_MENU;
  1113. X        break;
  1114. X     case 'n': /* ?no */
  1115. X        cmd = M_REJECT;
  1116. X        break;
  1117. X     case 's': /* ?show */
  1118. X        cmd = M_IS_SHOW;
  1119. X        break;
  1120. X     case 'y': /* ?yes */
  1121. X        cmd = M_CONFIRM;
  1122. X        break;
  1123. X     default:
  1124. X        m_error("unknown conditional %s", w - 1);
  1125. X        return 1;
  1126. X    }
  1127. X    m->m_type = cmd;
  1128. X    goto ok;
  1129. X    }
  1130. X
  1131. X    if ((cmd = lookup_command(w, (K_ONLY_MENU | K_ONLY_MORE))) != K_INVALID) {
  1132. X    m_new(M_COMMAND);
  1133. X    m->m_int = GETC_COMMAND | cmd;
  1134. X    goto ok;
  1135. X    }
  1136. X
  1137. X    if (strcmp(w, "prompt") == 0) {
  1138. X    m_new(M_PROMPT);
  1139. X    m->m_string = "?";
  1140. X    goto ok;
  1141. X    }
  1142. X    if (strcmp(w, "echo") == 0) {
  1143. X    m_new(M_ECHO);
  1144. X    m->m_string = "ups";
  1145. X    goto ok;
  1146. X    }
  1147. X    if (strcmp(w, "puts") == 0) {
  1148. X    m_new(M_PUTS);
  1149. X    m->m_string = "";
  1150. X    goto ok;
  1151. X    }
  1152. X    if (strcmp(w, "input") == 0) {
  1153. X    m_new(M_INPUT);
  1154. X    goto ok;
  1155. X    }
  1156. X    if (strcmp(w, "yes") == 0) {
  1157. X    m_new(M_YES);
  1158. X    goto ok;
  1159. X    }
  1160. X    if (strcmp(w, "no") == 0) {
  1161. X    m_new(M_NO);
  1162. X    goto ok;
  1163. X    }
  1164. X    if (strcmp(w, "break") == 0) {
  1165. X    m_new(M_BREAK);
  1166. X    goto ok;
  1167. X    }
  1168. X    if (strcmp(w, "return") == 0) {
  1169. X    m_new(M_RETURN);
  1170. X    goto ok;
  1171. X    }
  1172. X
  1173. X    m_error("Unknown word >>%s<<", w);
  1174. X    return 1;
  1175. X
  1176. X ok:
  1177. X    return 0;
  1178. X}
  1179. X
  1180. Xstatic parse_line(lp)
  1181. Xchar *lp;
  1182. X{
  1183. X    char *word;
  1184. X    struct macro *m1, *branch = NULL;
  1185. X
  1186. X    while (*lp) {
  1187. X    if (*lp == '#') break;
  1188. X
  1189. X    if (*lp == ':') {
  1190. X        lp++;
  1191. X        if (initial_set_commands) {
  1192. X        if (strncmp(lp, "local",  5) == 0 ||
  1193. X            strncmp(lp, "set",    3) == 0 ||
  1194. X            strncmp(lp, "unset",  5) == 0) {
  1195. X            m_new(M_SET_COMMAND);
  1196. X            m->m_string = copy_str(lp);
  1197. X            break;
  1198. X        }
  1199. X        initial_set_commands = 0;
  1200. X        }
  1201. X        m_new(M_COMMAND);
  1202. X        m->m_int = GETC_COMMAND | K_EXTENDED_CMD;
  1203. X        m_new(M_STRING);
  1204. X        m->m_string = copy_str(lp);
  1205. X        break;
  1206. X    }
  1207. X    initial_set_commands = 0;
  1208. X
  1209. X    if (*lp == '?') {
  1210. X        m_new(M_IS_MENU);
  1211. X        if (branch == NULL) {
  1212. X        m1 = m;
  1213. X        m_new(M_DUMMY);
  1214. X        branch = m;
  1215. X        m = m1;
  1216. X        }
  1217. X        m->m_branch = branch;
  1218. X    }
  1219. X
  1220. X    word = lp;
  1221. X    if (*lp == '"')
  1222. X        do lp++;
  1223. X        while (*lp && *lp != '"');
  1224. X    else
  1225. X    if (*lp == '\'')
  1226. X        do lp++;
  1227. X        while (*lp && *lp != '\'');
  1228. X    else
  1229. X        while (*lp && !isspace(*lp)) lp++;
  1230. X    if (*lp) {
  1231. X        *lp++ = NUL;
  1232. X        while (*lp && isspace(*lp)) lp++;
  1233. X    }
  1234. X    if (parse_word(word)) return 1;
  1235. X    }
  1236. X
  1237. X    if (branch) {
  1238. X    m->m_next = branch;
  1239. X    m = branch;
  1240. X    }
  1241. X    return 0;
  1242. X}
  1243. X
  1244. Xchar *m_define(id, f)
  1245. Xchar *id;
  1246. XFILE *f;
  1247. X{
  1248. X    char line[256], *lp, skip;
  1249. X    int type = 0;
  1250. X
  1251. X    if (id) {
  1252. X    cur_m = atoi(id);
  1253. X    if (cur_m == -1) {
  1254. X        cur_m = NMACRO;    /* special slot for this purpose */
  1255. X    } else if (cur_m == -2) {
  1256. X        for (cur_m = NUM_MACRO; cur_m < NMACRO; cur_m++)
  1257. X        if (macro[cur_m] == NULL) break;
  1258. X        if (cur_m == NMACRO) {
  1259. X        init_message("No unused macro slots");
  1260. X        return (char *)K_UNBOUND;
  1261. X        }
  1262. X        type = 1;
  1263. X    } else if (cur_m < 0 || cur_m >= NUM_MACRO) {
  1264. X        m_error("macro number out of range\n", id);
  1265. X        return (char *)0;
  1266. X    }
  1267. X    } else {
  1268. X    for (cur_m = 0; cur_m < NUM_MACRO; cur_m++)
  1269. X        if (macro[cur_m] == NULL) break;
  1270. X    if (cur_m == NUM_MACRO) {
  1271. X        init_message("No unused macro numbers");
  1272. X        return (char *)0;
  1273. X    }
  1274. X    }
  1275. X
  1276. X    if (f == NULL) {
  1277. X    clrdisp();
  1278. X    printf("DEFINE %sMACRO %d -- END WITH 'end'\n\n\r",
  1279. X           cur_m >= NUM_MACRO ? "ANONYMOUS " : "",
  1280. X           cur_m >= NUM_MACRO ? cur_m - NUM_MACRO : cur_m);
  1281. X    unset_raw();
  1282. X    f = stdin;
  1283. X    }
  1284. X
  1285. X    m = NULL;
  1286. X    skip = 0;
  1287. X    initial_set_commands = (cur_m == NMACRO);
  1288. X
  1289. X    while (fgets(line, 256, f)) {
  1290. X    for (lp = line; *lp && isspace(*lp); lp++);
  1291. X    if (*lp == NUL) continue;
  1292. X    if (*lp == ')' || strncmp(lp, "end", 3) == 0) goto out;
  1293. X    if (!skip && parse_line(lp)) {
  1294. X        macro[cur_m] = NULL;
  1295. X        skip++;
  1296. X    }
  1297. X    }
  1298. X
  1299. X    if (f != stdin)
  1300. X    m_error("end missing", (char *)NULL);
  1301. X
  1302. X out:
  1303. X    if (f == stdin) raw();
  1304. X    m = NULL;
  1305. X    return type == 0 ? (char *)macro[cur_m] : (char *)(K_MACRO | cur_m);
  1306. X}
  1307. X
  1308. Xchar *m_get_macro(id)
  1309. Xchar *id;
  1310. X{
  1311. X    if (id) {
  1312. X    cur_m = atoi(id);
  1313. X    if (cur_m < 0 || cur_m >= NMACRO) {
  1314. X        m_error("macro number out of range\n", id);
  1315. X        return (char *)0;
  1316. X    }
  1317. X    }
  1318. X    return (char *)macro[cur_m];
  1319. X}
  1320. X
  1321. Xchar *parse_enter_macro(f, c)
  1322. XFILE *f;
  1323. Xregister int c;
  1324. X{
  1325. X    register char *gp;
  1326. X    char other[FILENAME];
  1327. X    group_header *gh;
  1328. X    static char *last_defined = NULL;
  1329. X
  1330. X    while (c != EOF && c != NL && (!isascii(c) || isspace(c))) c = getc(f);
  1331. X
  1332. X    if (c == ')') return last_defined;
  1333. X
  1334. X    if (c == EOF) return (char *)NULL;
  1335. X
  1336. X    if (c == NL) return last_defined = m_define("-1", f);
  1337. X
  1338. X    gp = other;
  1339. X    do {
  1340. X    *gp++ = c;
  1341. X    c = getc(f);
  1342. X    } while (c != EOF && c != ')' && isascii(c) && !isspace(c));
  1343. X
  1344. X    *gp = NUL;
  1345. X    if (gh = lookup(other)) return gh->enter_macro;
  1346. X
  1347. X    return m_get_macro(other);
  1348. X}
  1349. X
  1350. X/*
  1351. X *    Invoke macro # N
  1352. X */
  1353. X
  1354. Xm_invoke(n)
  1355. Xint n;
  1356. X{
  1357. X    if (n < 0) {
  1358. X    n = NMACRO;
  1359. X    if ((macro[n] = (struct macro *)(current_group->enter_macro)) == NULL)
  1360. X        if ((macro[n] = (struct macro *)dflt_enter_macro) == NULL)
  1361. X        return;
  1362. X    } else
  1363. X    if (n >= NMACRO || macro[n] == NULL) {
  1364. X    msg("undefined macro %d", n);
  1365. X    return;
  1366. X    }
  1367. X
  1368. X    if (m_level == 0)
  1369. X    no_advance = 0;
  1370. X    else {
  1371. X    if (m_level > MSTACK) {
  1372. X        msg("Macro stack overflow");
  1373. X        m_break();
  1374. X        return;
  1375. X    }
  1376. X    mstack[m_level] = m;
  1377. X    cstack[m_level] = cur_m;
  1378. X    }
  1379. X    m_level++;
  1380. X
  1381. X    cur_m = n;
  1382. X    m = macro[cur_m];
  1383. X    while (m && m->m_type == M_SET_COMMAND) {
  1384. X    char buffer[128];
  1385. X    strcpy(buffer, m->m_string);
  1386. X    if (macro_debug) { msg(":%s", buffer); user_delay(1); }
  1387. X    parse_command(buffer, 0, (FILE *)NULL);
  1388. X    m = m->m_next;
  1389. X    }
  1390. X}
  1391. X
  1392. Xm_startinput()
  1393. X{
  1394. X    no_advance = 1;
  1395. X}
  1396. X
  1397. Xm_endinput()
  1398. X{
  1399. X    if (no_advance) {
  1400. X    no_advance = 0;
  1401. X    if (m && m->m_type == M_INPUT)
  1402. X        m = m->m_next;
  1403. X    }
  1404. X}
  1405. X
  1406. Xm_advinput()
  1407. X{
  1408. X    if (m && m->m_type == M_INPUT)
  1409. X    m = m->m_next;
  1410. X}
  1411. X
  1412. Xstatic struct macro *m_call(who)
  1413. Xint who;
  1414. X{
  1415. X    struct macro *m1;
  1416. X
  1417. X    for (;;) {
  1418. X    while (m == NULL && m_level > 1) {
  1419. X        m_level--;
  1420. X        m = mstack[m_level];
  1421. X        cur_m = cstack[m_level];
  1422. X    }
  1423. X    if (m == NULL) {
  1424. X        if (macro_debug) msg("end");
  1425. X        m_break();
  1426. X        return NULL;
  1427. X    }
  1428. X
  1429. X    if (macro_debug)
  1430. X        macro_dbg();
  1431. X
  1432. X    if (who == 3) {
  1433. X        if (m->m_type == M_YES || m->m_type == M_NO) goto out;
  1434. X        return NULL;
  1435. X    }
  1436. X
  1437. X    switch (m->m_type) {
  1438. X     case M_COMMAND:
  1439. X        if (m->m_int == (GETC_COMMAND | K_REDRAW))
  1440. X        changed_prompt = 0;
  1441. X     case M_KEY:
  1442. X        if (who == 1) goto out;
  1443. X        goto err;
  1444. X
  1445. X     case M_STRING:
  1446. X        if (who == 2) goto out;
  1447. X        goto err;
  1448. X
  1449. X     case M_INPUT:
  1450. X        if (no_advance) return m;
  1451. X        goto out;
  1452. X
  1453. X     case M_YES:
  1454. X     case M_NO:
  1455. X     case M_DUMMY:
  1456. X        break;
  1457. X
  1458. X     case M_PUTS:
  1459. X        fputs(m->m_string, stdout); fl;
  1460. X        break;
  1461. X
  1462. X     case M_PROMPT:
  1463. X        if (m->m_string[0] == NUL) {
  1464. X        changed_prompt = 0;
  1465. X        break;
  1466. X        }
  1467. X        if (!changed_prompt) prompt(P_SAVE);
  1468. X        changed_prompt = 1;
  1469. X        prompt("\1%s\1 ", m->m_string);
  1470. X        break;
  1471. X
  1472. X     case M_ECHO:
  1473. X        msg(m->m_string);
  1474. X        restore_xy();
  1475. X        break;
  1476. X
  1477. X     case M_IS_MENU:
  1478. X        if (!in_menu_mode) m = m->m_branch;
  1479. X        break;
  1480. X     case M_IS_SHOW:
  1481. X        if (in_menu_mode) m = m->m_branch;
  1482. X        break;
  1483. X     case M_IS_GROUP:
  1484. X        if (current_group->group_flag & G_FOLDER) m = m->m_branch;
  1485. X        break;
  1486. X     case M_IS_FOLDER:
  1487. X        if ((current_group->group_flag & G_FOLDER) == 0) m = m->m_branch;
  1488. X        break;
  1489. X     case M_CONFIRM:
  1490. X        if (yes(0) == 0) m = m->m_branch;
  1491. X        break;
  1492. X     case M_REJECT:
  1493. X        if (yes(0) == 1) m = m->m_branch;
  1494. X        break;
  1495. X
  1496. X     case M_VARTEST:
  1497. X        m1 = m;
  1498. X        m = m->m_next;
  1499. X
  1500. X        switch (test_variable(m1->m_string)) {
  1501. X         case 0:
  1502. X        m = m->m_branch;
  1503. X        break;
  1504. X         case -1:
  1505. X        goto err1;
  1506. X        }
  1507. X        break;
  1508. X
  1509. X     case M_RETURN:
  1510. X        m = NULL;
  1511. X        continue;
  1512. X
  1513. X     case M_BREAK:
  1514. X        goto term;
  1515. X    }
  1516. X
  1517. X    if (m) m = m->m_next;
  1518. X    }
  1519. X
  1520. X out:
  1521. X    m1 = m;
  1522. X    m = m->m_next;
  1523. X    no_advance = 0;
  1524. X    return m1;
  1525. X
  1526. X err:
  1527. X    msg("Error in macro %d", cur_m);
  1528. X err1:
  1529. X    user_delay(1);
  1530. X    m_break();
  1531. X    return MERROR;
  1532. X
  1533. X term:
  1534. X    m_break();
  1535. X    return NULL;
  1536. X}
  1537. X
  1538. Xm_break_entry()
  1539. X{
  1540. X    if (current_group->enter_macro || dflt_enter_macro)
  1541. X    m = NULL;
  1542. X}
  1543. X
  1544. Xm_break()
  1545. X{
  1546. X    if (changed_prompt) prompt(P_RESTORE);
  1547. X    changed_prompt = 0;
  1548. X    m = NULL;
  1549. X    m_level = 0;
  1550. X}
  1551. X
  1552. Xmacro_dbg()
  1553. X{
  1554. X    extern char *command_name();
  1555. X    char *name;
  1556. X
  1557. X    switch (m->m_type) {
  1558. X     case M_COMMAND:
  1559. X    msg("COMMAND: %s", command_name(m->m_int));
  1560. X    goto delay;
  1561. X
  1562. X     case M_KEY:
  1563. X    msg("KEY: %s", key_name((key_type)(m->m_int)));
  1564. X    goto delay;
  1565. X
  1566. X     case M_STRING:
  1567. X    msg("STRING: %s", m->m_string);
  1568. X    goto delay;
  1569. X
  1570. X     case M_INPUT:
  1571. X    name = "input";
  1572. X    break;
  1573. X
  1574. X     case M_YES:
  1575. X    name = "yes";
  1576. X    break;
  1577. X
  1578. X     case M_NO:
  1579. X    name = "no";
  1580. X    break;
  1581. X
  1582. X     case M_DUMMY:
  1583. X    name = "dummy";
  1584. X    break;
  1585. X
  1586. X     case M_PROMPT:
  1587. X    msg("PROMPT: %s", m->m_string);
  1588. X    goto delay;
  1589. X
  1590. X     case M_ECHO:
  1591. X    msg("ECHO: %s", m->m_string);
  1592. X    goto delay;
  1593. X
  1594. X     case M_IS_MENU:
  1595. X    msg("?menu => %d", in_menu_mode);
  1596. X    goto delay;
  1597. X
  1598. X     case M_IS_SHOW:
  1599. X    msg("?show => %d", !in_menu_mode);
  1600. X    goto delay;
  1601. X
  1602. X     case M_IS_GROUP:
  1603. X    msg("?group => %d", (current_group->group_flag & G_FOLDER) == 0);
  1604. X    goto delay;
  1605. X
  1606. X     case M_IS_FOLDER:
  1607. X    msg("?group => %d", (current_group->group_flag & G_FOLDER));
  1608. X    goto delay;
  1609. X
  1610. X     case M_CONFIRM:
  1611. X    name = "?yes";
  1612. X    break;
  1613. X
  1614. X     case M_REJECT:
  1615. X    name = "?no";
  1616. X    break;
  1617. X
  1618. X     case M_VARTEST:
  1619. X    msg("?%s => %d", m->m_string, test_variable(m->m_string));
  1620. X    goto delay;
  1621. X
  1622. X     case M_RETURN:
  1623. X    name = "return";
  1624. X    break;
  1625. X
  1626. X     case M_BREAK:
  1627. X    name = "break";
  1628. X    break;
  1629. X    }
  1630. X    msg(name);
  1631. X
  1632. X delay:
  1633. X    user_delay(1);
  1634. X}
  1635. X
  1636. X/*
  1637. X *    Macro processing for get_c()
  1638. X */
  1639. X
  1640. Xm_getc(cp)
  1641. Xint *cp;
  1642. X{
  1643. X    struct macro *m1;
  1644. X
  1645. X    get_from_macro = 0;
  1646. X    if (m_level && (m1 = m_call(1))) {
  1647. X    if (m1 == MERROR) return 2;
  1648. X    if (m1->m_type == M_INPUT) return 0;
  1649. X    *cp = m1->m_int;
  1650. X    get_from_macro = 1;
  1651. X    return 1;
  1652. X    }
  1653. X    return 0;
  1654. X}
  1655. X
  1656. X/*
  1657. X *    Macro processing for get_s()
  1658. X */
  1659. X
  1660. Xm_gets(s)
  1661. Xchar *s;
  1662. X{
  1663. X    struct macro *m1;
  1664. X
  1665. X    get_from_macro = 0;
  1666. X    if (m_level && (m1 = m_call(2))) {
  1667. X    if (m1 == MERROR) return 2;
  1668. X    if (m1->m_type == M_INPUT) return 0;
  1669. X    strcpy(s, m1->m_string);
  1670. X    get_from_macro = 1;
  1671. X    return 1;
  1672. X    }
  1673. X    return 0;
  1674. X}
  1675. X
  1676. X/*
  1677. X *    Macro processing for yes()
  1678. X */
  1679. X
  1680. Xm_yes()
  1681. X{
  1682. X    struct macro *m1;
  1683. X
  1684. X    if (m)
  1685. X    if (m->m_type == M_CONFIRM || m->m_type == M_REJECT) return 3;
  1686. X
  1687. X    if (m_level) {
  1688. X    if (m1 = m_call(3))
  1689. X        if (m1->m_type == M_NO)
  1690. X        return 1;
  1691. X        else
  1692. X        return 2;
  1693. X    else
  1694. X        return 3;
  1695. X    }
  1696. X    return 0;
  1697. X}
  1698. END_OF_FILE
  1699.   if test 14186 -ne `wc -c <'macro.c'`; then
  1700.     echo shar: \"'macro.c'\" unpacked with wrong size!
  1701.   fi
  1702.   # end of 'macro.c'
  1703. fi
  1704. if test -f 'nn.c' -a "${1}" != "-c" ; then 
  1705.   echo shar: Will not clobber existing file \"'nn.c'\"
  1706. else
  1707.   echo shar: Extracting \"'nn.c'\" \(17064 characters\)
  1708.   sed "s/^X//" >'nn.c' <<'END_OF_FILE'
  1709. X/*
  1710. X *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  1711. X *
  1712. X *    The nn user interface main program
  1713. X */
  1714. X
  1715. X#include "config.h"
  1716. X#include "menu.h"
  1717. X#include "term.h"
  1718. X#include "keymap.h"
  1719. X#include "options.h"
  1720. X#include "proto.h"
  1721. X#include "articles.h"
  1722. X
  1723. Ximport char *bin_directory;
  1724. X
  1725. Ximport int
  1726. X    seq_cross_filtering,                    /* articles */
  1727. X    dont_sort_folders,                        /* folder.c */
  1728. X    dont_split_digests, dont_sort_articles, also_unsub_groups,    /* group.c */
  1729. X    also_cross_postings,
  1730. X    case_fold_search,                        /* match.c */
  1731. X    preview_window, fmt_linenum, fmt_rptsubj,            /* menu.c */
  1732. X    show_article_date, first_page_lines,            /* more.c */
  1733. X    keep_rc_backup, no_update,                    /* newsrc.c */
  1734. X    hex_group_args,                        /* sequence */
  1735. X    show_current_time, conf_dont_sleep;                /* term.c */
  1736. X
  1737. Xexport int
  1738. X    article_limit = -1,
  1739. X    also_read_articles = 0,
  1740. X    conf_auto_quit = 0,
  1741. X    do_kill_handling = 1,
  1742. X    group_name_args = 0,
  1743. X    merged_menu = 0,
  1744. X    repeat_group_query = 0,
  1745. X    report_cost_on_exit = 1,
  1746. X    silent = 0,
  1747. X    verbose = 0,
  1748. X    Debug = 0;
  1749. X
  1750. Xstatic int
  1751. X    nngrab_mode = 0,
  1752. X    prompt_for_group = 0;
  1753. X
  1754. Xstatic char
  1755. X    *match_subject = NULL,
  1756. X    *match_sender = NULL,
  1757. X    *init_file = NULL;
  1758. X
  1759. XOption_Description(nn_options) {
  1760. X    'a', Int_Option(article_limit),
  1761. X    'B', Bool_Option(keep_rc_backup),
  1762. X    'd', Bool_Option(dont_split_digests),
  1763. X    'f', Bool_Option(dont_sort_folders),
  1764. X    'g', Bool_Option(prompt_for_group),
  1765. X    'G', Bool_Option(nngrab_mode),
  1766. X    'i', Bool_Option(case_fold_search),
  1767. X    'I', String_Option_Optional(init_file, NULL),
  1768. X    'k', Bool_Option(do_kill_handling),
  1769. X    'l', Int_Option(first_page_lines),
  1770. X    'L', Int_Option_Optional(fmt_linenum, 3),
  1771. X    'm', Bool_Option(merged_menu),
  1772. X    'n', String_Option(match_sender),
  1773. X    'N', Bool_Option(no_update),
  1774. X    'q', Bool_Option(dont_sort_articles),
  1775. X    'Q', Bool_Option(silent),
  1776. X    'r', Bool_Option(repeat_group_query),
  1777. X    's', String_Option(match_subject),
  1778. X    'S', Bool_Option(fmt_rptsubj),
  1779. X    'T', Bool_Option(show_current_time),
  1780. X    'w', Int_Option_Optional(preview_window, 5),
  1781. X    'W', Bool_Option(conf_dont_sleep),
  1782. X    'x', Int_Option_Optional(also_read_articles, -1),
  1783. X    'X', Bool_Option(also_unsub_groups),
  1784. X    'Z', Int_Option(Debug),
  1785. X    '\0',
  1786. X};
  1787. X
  1788. X
  1789. Xstatic int
  1790. X    report_number_of_articles = 0;
  1791. Xstatic char
  1792. X    *check_message_format = NULL;
  1793. Ximport int
  1794. X    quick_unread_count;
  1795. X
  1796. XOption_Description(check_options) {
  1797. X    'Q', Bool_Option(silent),
  1798. X    'r', Bool_Option(report_number_of_articles),
  1799. X    'f', String_Option(check_message_format),
  1800. X    't', Bool_Option(verbose),
  1801. X    'v', Bool_Option(verbose),
  1802. X    'c', Bool_Option(quick_unread_count),
  1803. X    '\0',
  1804. X};
  1805. X
  1806. X/* program name == argv[0] without path */
  1807. X
  1808. Xchar *pname;
  1809. X
  1810. Xstatic int must_unlock = 0;
  1811. X
  1812. Xstatic int nn_locked()
  1813. X{
  1814. X    if (no_update) return 0;
  1815. X
  1816. X    switch (who_am_i) {
  1817. X     case I_AM_ADMIN:
  1818. X     case I_AM_CHECK:
  1819. X     case I_AM_POST:
  1820. X     case I_AM_GREP:
  1821. X     case I_AM_SPEW:
  1822. X    return 0;        /* will not update .newsrc */
  1823. X    }
  1824. X
  1825. X    if (proto_lock(I_AM_NN, PL_SET)) {
  1826. X    printf("\nAnother nn process is already running\n\n");
  1827. X    return 1;
  1828. X    }
  1829. X
  1830. X    must_unlock = 1;
  1831. X    return 0;
  1832. X}
  1833. X
  1834. Xstatic flag_type setup_access()
  1835. X{
  1836. X    flag_type access_mode = 0;
  1837. X
  1838. X    if (do_kill_handling)
  1839. X    access_mode |= ACC_DO_KILL;
  1840. X    if (also_cross_postings)
  1841. X    access_mode |= ACC_ALSO_CROSS_POSTINGS;
  1842. X    if (also_read_articles)
  1843. X    access_mode |= ACC_ALSO_READ_ARTICLES;
  1844. X    if (dont_split_digests)
  1845. X    access_mode |= ACC_DONT_SPLIT_DIGESTS;
  1846. X    if (dont_sort_articles)
  1847. X    access_mode |= ACC_DONT_SORT_ARTICLES;
  1848. X
  1849. X    return access_mode;
  1850. X}
  1851. X
  1852. Xexport group_header *jump_to_group = NULL;
  1853. X
  1854. Xstatic read_news(access_mode, mask)
  1855. Xflag_type access_mode;
  1856. Xchar *mask;
  1857. X{
  1858. X    register group_header *gh, *prev, *tmp, *after_loop;
  1859. X    flag_type group_mode;
  1860. X    int menu_cmd;
  1861. X    int must_clear = 0, did_jump = 0;
  1862. X    extern int menu();
  1863. X
  1864. X    prev = group_sequence;
  1865. X    gh = group_sequence;
  1866. X    after_loop = NULL;
  1867. X
  1868. X    for (;;) {
  1869. X    group_mode = access_mode;
  1870. X    
  1871. X    if (s_hangup) break;
  1872. X
  1873. X    if (gh == NULL) {
  1874. X        if (after_loop != NULL) {
  1875. X        gh = after_loop;
  1876. X        after_loop = NULL;
  1877. X        if (gh->unread_count <= 0)
  1878. X            group_mode |= ACC_ORIG_NEWSRC;
  1879. X        goto enter_direct;
  1880. X        }
  1881. X
  1882. X        if (did_jump) {
  1883. X        did_jump = 0;
  1884. X        gh = group_sequence;
  1885. X        continue;
  1886. X        }
  1887. X
  1888. X        if (must_clear && conf_auto_quit) {
  1889. X        prompt("\1LAST GROUP READ.  QUIT NOW?\1");
  1890. X        switch (yes(1)) {
  1891. X         case 1:
  1892. X            break;
  1893. X         case 0:
  1894. X            gh = group_sequence;
  1895. X         default:
  1896. X            after_loop = prev;
  1897. X            continue;
  1898. X        }
  1899. X        }
  1900. X        break;
  1901. X    }
  1902. X
  1903. X    if (gh->group_flag & G_UNSUBSCRIBED) {
  1904. X        if (!also_unsub_groups) {
  1905. X        gh = gh->next_group;
  1906. X        continue;
  1907. X        }
  1908. X    } else
  1909. X        if (!also_read_articles && gh->unread_count <= 0) {
  1910. X        gh = gh->next_group;
  1911. X        continue;
  1912. X        }
  1913. X
  1914. X     enter_direct:
  1915. X
  1916. X    free_memory();
  1917. X
  1918. X    if (gh->group_flag & G_FOLDER) {
  1919. X        menu_cmd = folder_menu(gh->group_name);
  1920. X        if (menu_cmd == ME_NO_REDRAW) {
  1921. X        menu_cmd = ME_NO_ARTICLES;
  1922. X        gh->last_db_article = 0;
  1923. X        }
  1924. X    } else {
  1925. X        group_mode |= setup_access();
  1926. X        if (group_mode & ACC_ORIG_NEWSRC)
  1927. X        gh->last_article = gh->first_article;
  1928. X        
  1929. X        menu_cmd = group_menu(gh, (article_number)(-1), group_mode, mask, menu);
  1930. X        group_mode = access_mode;
  1931. X    }
  1932. X
  1933. X    if (menu_cmd != ME_NO_ARTICLES) {
  1934. X        after_loop = NULL;
  1935. X        must_clear++;
  1936. X    }
  1937. X
  1938. X    switch (menu_cmd) {
  1939. X
  1940. X     case ME_QUIT:    /* or jump */
  1941. X        if (!jump_to_group) return must_clear;
  1942. X
  1943. X        prev = jump_to_group;
  1944. X        jump_to_group = NULL;
  1945. X        did_jump = 1;
  1946. X        /* fall thru */
  1947. X
  1948. X     case ME_PREV:
  1949. X        tmp = gh;
  1950. X        gh = prev;
  1951. X        prev = tmp;
  1952. X        if (gh->unread_count <= 0)
  1953. X        group_mode |= ACC_ORIG_NEWSRC;
  1954. X        goto enter_direct;
  1955. X
  1956. X     case ME_NEXT:
  1957. X        prev = gh;
  1958. X        /* fall thru */
  1959. X
  1960. X     case ME_NO_ARTICLES:
  1961. X        if (gh->group_flag & G_MERGE_HEAD) {
  1962. X        do gh = gh->next_group;
  1963. X            while (gh && (gh->group_flag & G_MERGE_SUB));
  1964. X        } else
  1965. X        gh = gh->next_group;
  1966. X        continue;
  1967. X    }
  1968. X    }
  1969. X    return must_clear;
  1970. X}
  1971. X
  1972. X
  1973. Xstatic catch_up()
  1974. X{
  1975. X    register group_header *gh;
  1976. X    char answer[50];
  1977. X    int mode, must_help;
  1978. X    import int newsrc_update_freq, novice;
  1979. X    import int menu();
  1980. X    flag_type access_mode;
  1981. X
  1982. X    access_mode = setup_access();
  1983. X    
  1984. X    prt_unread("\nCatch-up on %u ? (auto)matically (i)nteractive ");
  1985. X    fl;
  1986. X    mode = 0;
  1987. X
  1988. X    if (gets(answer)) {
  1989. X    if (strncmp(answer, "auto", 4) == 0) {
  1990. X        printf("\nUPDATING .newsrc FILE....");
  1991. X        fl;
  1992. X        mode = -1;
  1993. X    } else
  1994. X    if (*answer == 'i')
  1995. X        mode = 1;
  1996. X    }
  1997. X
  1998. X    if (mode == 0) {
  1999. X    printf("\nNO UPDATE\n");
  2000. X    return;
  2001. X    }
  2002. X
  2003. X    newsrc_update_freq = 9999;
  2004. X    must_help = novice;
  2005. X
  2006. X    Loop_Groups_Sequence(gh) {
  2007. X
  2008. X    if ((gh->group_flag & G_COUNTED) == 0) continue;
  2009. X
  2010. X    if (mode < 0) {
  2011. X        update_rc_all(gh, 0);
  2012. X        continue;
  2013. X    }
  2014. X
  2015. X     again:
  2016. X    if (must_help) {
  2017. X        printf("\n  y - mark all articles as read in current group\n");
  2018. X        printf("  n - do not update group\n");
  2019. X        printf("  r - read the group now\n");
  2020. X        printf("  U - unsubscribe to current group\n");
  2021. X        printf("  ? - this message\n");
  2022. X        printf("  q - quit\n\n");
  2023. X
  2024. X        must_help = 0;
  2025. X    }
  2026. X
  2027. X    printf("Update %s (%ld)? (ynrU?q) n\b", gh->group_name,
  2028. X           (long)(gh->last_db_article - gh->last_article));
  2029. X    fl;
  2030. X
  2031. X    if (gets(answer) == NULL || s_keyboard)
  2032. X        *answer = 'q';
  2033. X
  2034. X    switch (*answer) {
  2035. X
  2036. X     case 'q':
  2037. X        putchar(NL);
  2038. X        printf("Update rest? (yn) n\b");
  2039. X        fl;
  2040. X        if (gets(answer) == NULL || *answer != 'y')
  2041. X        return;
  2042. X
  2043. X        mode = -1;
  2044. X        break;
  2045. X
  2046. X     case NUL:
  2047. X     case 'n':
  2048. X        continue;
  2049. X
  2050. X     case 'r':
  2051. X        raw();
  2052. X        group_menu(gh, (article_number)(-1), access_mode, (char *)NULL, menu);
  2053. X        unset_raw();
  2054. X        clrdisp();
  2055. X        if (gh->unread_count > 0) goto again;
  2056. X        continue;
  2057. X
  2058. X     case 'U':
  2059. X        update_rc_all(gh, 1);
  2060. X        continue;
  2061. X
  2062. X     case 'y':
  2063. X        break;
  2064. X
  2065. X     default:
  2066. X        must_help = 1;
  2067. X        goto again;
  2068. X    }
  2069. X
  2070. X    update_rc_all(gh, 0);
  2071. X    }
  2072. X
  2073. X    printf("DONE\n");
  2074. X
  2075. X    flush_newsrc();
  2076. X}
  2077. X
  2078. Xexport char *mail_box = NULL;
  2079. X
  2080. Xunread_mail(t)
  2081. Xtime_t t;
  2082. X{
  2083. X    struct stat st;
  2084. X    static time_t next = 0;
  2085. X    static int any = 0;
  2086. X
  2087. X    if (next > t) return any;
  2088. X
  2089. X    next = t + 60;
  2090. X    any = 0;
  2091. X
  2092. X    if (mail_box == NULL ||
  2093. X    stat(mail_box, &st) != 0 ||
  2094. X    st.st_size == 0 ||
  2095. X    st.st_mtime < st.st_atime) return 0;
  2096. X
  2097. X    any = 1;
  2098. X
  2099. X    return 1;
  2100. X}
  2101. X
  2102. X#ifdef ACCOUNTING
  2103. X#ifndef STATISTICS
  2104. X#define STATISTICS 1
  2105. X#endif
  2106. X#define NEED_ACCOUNT
  2107. X#else
  2108. X#ifdef AUTHORIZE
  2109. X#define NEED_ACCOUNT
  2110. X#endif
  2111. X#endif
  2112. X
  2113. X#ifdef STATISTICS
  2114. Xstatic time_t usage_time = 0;
  2115. Xstatic time_t last_tick = 0;
  2116. X
  2117. Xstop_usage()
  2118. X{
  2119. X    last_tick = 0;
  2120. X}
  2121. X
  2122. Xtime_t tick_usage()
  2123. X{
  2124. X    register time_t now;
  2125. X
  2126. X    now = cur_time();
  2127. X
  2128. X    /*
  2129. X     * We ignore ticks > 2 minutes because the user has probably
  2130. X     * just left the terminal inside nn and done something else
  2131. X     */
  2132. X    if (last_tick > (now - 120))
  2133. X    usage_time += now - last_tick;
  2134. X
  2135. X    last_tick = now;
  2136. X    return now;
  2137. X}
  2138. X
  2139. Xlog_usage()
  2140. X{
  2141. X#ifdef ACCOUNTING
  2142. X    account('U', report_cost_on_exit);
  2143. X#else
  2144. X    if (usage_time < (STATISTICS * 60)) return; /* don't log short sessions */
  2145. X
  2146. X    usage_time /= 60;
  2147. X    log_entry('U', "USAGE %d.%02d", usage_time/60, usage_time%60);
  2148. X#endif
  2149. X}
  2150. X
  2151. X#else
  2152. Xstop_usage()
  2153. X{
  2154. X}
  2155. X
  2156. Xtime_t tick_usage()
  2157. X{
  2158. X    return cur_time();
  2159. X}
  2160. X
  2161. Xlog_usage()
  2162. X{
  2163. X}
  2164. X#endif
  2165. X
  2166. X#ifdef NEED_ACCOUNT
  2167. Xaccount(option, report)
  2168. Xchar option;
  2169. Xint report;
  2170. X{
  2171. X    char *args[10], **ap;
  2172. X    char buf1[16], buf2[16];
  2173. X    int ok;
  2174. X
  2175. X    if (who_am_i != I_AM_NN && who_am_i != I_AM_POST) return 0;
  2176. X
  2177. X    if (report) {
  2178. X    putchar(CR); clrline(); fl;
  2179. X    }
  2180. X
  2181. X    ap = args;
  2182. X    *ap++ = "nnacct";
  2183. X    if (report) *ap++ = "-r";
  2184. X    sprintf(buf1, "-%c%ld", option, (long)usage_time/60);
  2185. X    *ap++ = buf1;
  2186. X    sprintf(buf2, "-W%d", who_am_i);
  2187. X    *ap++ = buf2;
  2188. X    *ap++ = NULL;
  2189. X    ok = execute(relative(bin_directory, "nnacct"), args, 0);
  2190. X    if (option == 'U' && report) putchar(NL);
  2191. X    return ok;
  2192. X}
  2193. X#endif
  2194. X
  2195. X/* this will go into emacs_mode.c when it is completed someday */
  2196. X
  2197. Xemacs_mode()
  2198. X{
  2199. X    printf("EMACS MODE IS NOT SUPPORTED YET.\n");
  2200. X}
  2201. X
  2202. X
  2203. Xstatic do_nnspew()
  2204. X{
  2205. X    register group_header *gh;
  2206. X    import int seq_cross_filtering;
  2207. X    int ix;
  2208. X
  2209. X    ix = 0;
  2210. X    Loop_Groups_Header(gh) {
  2211. X    if (gh->master_flag & M_IGNORE_GROUP) continue;
  2212. X    gh->preseq_index = ++ix;
  2213. X    }
  2214. X
  2215. X    /* Only output each article once */
  2216. X    /* Must also use this mode when using nngrab! */
  2217. X
  2218. X    seq_cross_filtering = 1;
  2219. X
  2220. X    Loop_Groups_Header(gh) {
  2221. X    if (s_hangup) return 1;
  2222. X    if (gh->master_flag & M_IGNORE_GROUP) continue;
  2223. X    access_group(gh, gh->first_db_article, gh->last_db_article,
  2224. X             ACC_DONT_SORT_ARTICLES | ACC_ALSO_FULL_DIGEST |
  2225. X             ACC_SPEW_MODE, (char *)NULL);
  2226. X    }
  2227. X    return 0;
  2228. X}
  2229. X
  2230. X
  2231. Xclean_group(gh)
  2232. Xgroup_header *gh;
  2233. X{
  2234. X}
  2235. X
  2236. Xmain(argc, argv)
  2237. Xint argc;
  2238. Xchar *argv[];
  2239. X{
  2240. X    extern long unread_articles;
  2241. X    extern char *program_name();
  2242. X    int say_welcome = 0, cmd;
  2243. X    flag_type access_mode;
  2244. X    char *mask;
  2245. X
  2246. X    pname = program_name(argv);
  2247. X
  2248. X    if (strcmp(pname, "nnadmin") == 0) {
  2249. X    who_am_i = I_AM_ADMIN;
  2250. X    } else
  2251. X    if (strcmp(pname, "nnemacs") == 0) {
  2252. X    who_am_i = I_AM_EMACS;
  2253. X    } else
  2254. X    if (strcmp(pname, "nncheck") == 0) {
  2255. X    who_am_i = I_AM_CHECK;
  2256. X    } else
  2257. X    if (strcmp(pname, "nntidy") == 0) {
  2258. X    who_am_i = I_AM_TIDY;
  2259. X    } else
  2260. X    if (strcmp(pname, "nngoback") == 0) {
  2261. X    who_am_i = I_AM_GOBACK;
  2262. X    } else
  2263. X    if (strcmp(pname, "nngrep") == 0) {
  2264. X    who_am_i = I_AM_GREP;
  2265. X    } else
  2266. X    if (strcmp(pname, "nnpost") == 0) {
  2267. X    who_am_i = I_AM_POST;
  2268. X    } else {
  2269. X    who_am_i = I_AM_NN;
  2270. X    }
  2271. X
  2272. X    if (who_am_i == I_AM_NN || (who_am_i == I_AM_ADMIN && argc == 1)) {
  2273. X    if (!isatty(0)) {
  2274. X        if (who_am_i == I_AM_NN && argc == 2) {
  2275. X        if (strcmp(argv[1], "-SPEW") == 0) {
  2276. X            who_am_i = I_AM_SPEW;
  2277. X            init_global();
  2278. X            goto nnspew;
  2279. X        }
  2280. X        }
  2281. X
  2282. X        fprintf(stderr, "Input is not a tty\n");
  2283. X        exit(1);
  2284. X    }
  2285. X    }
  2286. X
  2287. X#ifdef AUTHORIZE
  2288. X    init_execute();
  2289. X    if (cmd = account('P', 0)) {
  2290. X    switch (cmd) {
  2291. X     case 1:
  2292. X        if (who_am_i == I_AM_POST) {
  2293. X        printf("You are not authorized to post news\n");
  2294. X        exit(41);
  2295. X        }
  2296. X        /* ok_to_post = 0; */
  2297. X        cmd = 0;
  2298. X        break;
  2299. X     case 2:
  2300. X        printf("You are not authorized to read news\n");
  2301. X        break;
  2302. X     case 3:
  2303. X        printf("You cannot read news at this time\n");
  2304. X        break;
  2305. X     case 4:
  2306. X        printf("Your news reading quota is exceeded\n");
  2307. X        break;
  2308. X     default:
  2309. X        printf("Bad authorization -- reason %d\n", cmd);
  2310. X        break;
  2311. X    }
  2312. X    if (cmd) exit(40 + cmd);
  2313. X    }
  2314. X#endif
  2315. X
  2316. X    if ((say_welcome = init_global()) < 0) {
  2317. X    printf("%s: nn must been invoked to initialize user files\n", pname);
  2318. X    nn_exit(1);
  2319. X    }
  2320. X
  2321. X#ifdef NNTP
  2322. X    nntp_check();
  2323. X#endif
  2324. X
  2325. X    init_key_map();
  2326. X#ifndef AUTHORIZE
  2327. X    init_execute();
  2328. X#endif
  2329. X    init_macro();
  2330. X
  2331. X nnspew:
  2332. X
  2333. X    open_master(OPEN_READ);
  2334. X
  2335. X    switch (who_am_i) {
  2336. X
  2337. X     case I_AM_NN:
  2338. X    init_term();
  2339. X
  2340. X    if (say_welcome) {
  2341. X        display_file("adm.welcome", CLEAR_DISPLAY | CONFIRMATION);
  2342. X        clrdisp();
  2343. X    }
  2344. X
  2345. X    visit_init_file(0, argv[1]);
  2346. X
  2347. X    group_name_args =
  2348. X        parse_options(argc, argv, (char *)NULL, nn_options,
  2349. X              " [group | [+]folder]...");
  2350. X
  2351. X    if (also_read_articles) {
  2352. X        if (article_limit < 0)
  2353. X        article_limit = also_read_articles;
  2354. X        do_kill_handling = 0;
  2355. X        no_update++;
  2356. X    }
  2357. X
  2358. X    if (match_subject) {
  2359. X        mask = match_subject;
  2360. X        access_mode = ACC_ON_SUBJECT;
  2361. X    } else if (match_sender) {
  2362. X        mask = match_sender;
  2363. X        access_mode = ACC_ON_SENDER;
  2364. X    } else {
  2365. X        mask = NULL;
  2366. X        access_mode = 0;
  2367. X    }
  2368. X
  2369. X    if (mask) {
  2370. X        if (case_fold_search) fold_string(mask);
  2371. X        no_update++;
  2372. X        do_kill_handling = 0;
  2373. X    }
  2374. X
  2375. X    if (nngrab_mode) {
  2376. X        seq_cross_filtering = 1;
  2377. X        hex_group_args = 1;
  2378. X        no_update = 1;
  2379. X    }
  2380. X
  2381. X    if (merged_menu) {
  2382. X        no_update++;
  2383. X    }
  2384. X
  2385. X    if (!no_update && group_name_args > 0)
  2386. X        no_update = only_folder_args(argv + 1);
  2387. X
  2388. X    break;
  2389. X
  2390. X     case I_AM_ADMIN:
  2391. X    if (argc == 1) {
  2392. X        init_term();
  2393. X        visit_init_file(0, (char *)NULL);
  2394. X    }
  2395. X    admin_mode(argv[1]);
  2396. X    nn_exit(0);
  2397. X
  2398. X     case I_AM_CHECK:
  2399. X    visit_init_file(1, (char *)NULL);
  2400. X    group_name_args =
  2401. X        parse_options(argc, argv, (char *)NULL, check_options,
  2402. X              " [group]...");
  2403. X    break;
  2404. X
  2405. X     case I_AM_EMACS:
  2406. X    silent = 1;
  2407. X    break;
  2408. X
  2409. X     case I_AM_TIDY:
  2410. X    visit_init_file(1, (char *)NULL);
  2411. X    group_name_args = opt_nntidy(argc, argv);
  2412. X    break;
  2413. X
  2414. X     case I_AM_GOBACK:
  2415. X    group_name_args = opt_nngoback(argc, &argv);
  2416. X    break;
  2417. X
  2418. X     case I_AM_GREP:
  2419. X    visit_init_file(1, (char *)NULL);
  2420. X    opt_nngrep(argc, argv);
  2421. X    silent = 1;
  2422. X    break;
  2423. X
  2424. X     case I_AM_POST:
  2425. X    do_nnpost(argc, argv);
  2426. X    nn_exit(0);
  2427. X
  2428. X     case I_AM_SPEW:
  2429. X    if (proto_lock(I_AM_SPEW, PL_SET) == 0) {
  2430. X        cmd = do_nnspew();
  2431. X        proto_lock(I_AM_SPEW, PL_CLEAR);
  2432. X    } else
  2433. X        cmd = 1;    /* don't interfere with other nnspew */
  2434. X    nn_exit(cmd);
  2435. X    }
  2436. X
  2437. X    if (!silent || who_am_i == I_AM_CHECK)
  2438. X    printf("Release %s,  Kim F. Storm, 1990\n\n", version_id);
  2439. X
  2440. X    if (nn_locked()) nn_exit(2);
  2441. X
  2442. X    visit_rc_file();
  2443. X
  2444. X    if (group_name_args > 0)
  2445. X    named_group_sequence(argv + 1);
  2446. X    else
  2447. X    normal_group_sequence();
  2448. X
  2449. X    if (who_am_i != I_AM_TIDY && who_am_i != I_AM_GOBACK)
  2450. X    count_unread_articles();
  2451. X
  2452. X    switch (who_am_i) {
  2453. X
  2454. X     case I_AM_EMACS:
  2455. X    prt_unread("%U %G\n");
  2456. X    emacs_mode();
  2457. X    break;
  2458. X
  2459. X     case I_AM_CHECK:
  2460. X    if (report_number_of_articles) {
  2461. X        prt_unread("%U");
  2462. X        break;
  2463. X    }
  2464. X
  2465. X    if (check_message_format) {
  2466. X        if (unread_articles || !silent)
  2467. X        prt_unread(check_message_format);
  2468. X    } else
  2469. X    if (!silent) {
  2470. X        if (unread_articles || report_number_of_articles)
  2471. X        prt_unread("There %i %u in %g\n");
  2472. X        else
  2473. X        prt_unread((char *)NULL);
  2474. X    }
  2475. X
  2476. X    nn_exit( unread_articles ? 0 : 99 );
  2477. X    /*NOTREACHED*/
  2478. X
  2479. X     case I_AM_TIDY:
  2480. X    do_tidy_newsrc();
  2481. X    break;
  2482. X
  2483. X     case I_AM_GOBACK:
  2484. X    do_goback();
  2485. X    break;
  2486. X
  2487. X     case I_AM_NN:
  2488. X    if (unread_articles == 0 &&
  2489. X        group_name_args == 0 &&
  2490. X        !also_read_articles &&
  2491. X        !prompt_for_group) {
  2492. X        if (!silent) prt_unread((char *)NULL);
  2493. X        break;
  2494. X    }
  2495. X
  2496. X    if (do_kill_handling)
  2497. X        do_kill_handling = init_kill();
  2498. X
  2499. X    if (prompt_for_group) {
  2500. X        import int also_cross_postings;
  2501. X
  2502. X        if (mask != NULL)
  2503. X        user_error("Cannot use -s/-n with -g\n\r");
  2504. X        
  2505. X        also_cross_postings = 1;
  2506. X        do {
  2507. X        raw();
  2508. X        clrdisp();
  2509. X        current_group = NULL;
  2510. X        prompt_line = 2;
  2511. X        cmd = goto_group(K_GOTO_GROUP, (article_header *)NULL, setup_access());
  2512. X        
  2513. X        } while (repeat_group_query && cmd != ME_QUIT && cmd != ME_NO_REDRAW);
  2514. X        clrdisp();
  2515. X        unset_raw();
  2516. X        break;
  2517. X    }
  2518. X
  2519. X    if (!no_update && article_limit == 0) {
  2520. X        catch_up();
  2521. X        break;
  2522. X    }
  2523. X
  2524. X    if (merged_menu) {
  2525. X        merge_and_read(access_mode | setup_access(), mask);
  2526. X        clrdisp();
  2527. X        break;
  2528. X    }
  2529. X
  2530. X    if (read_news(access_mode, mask)) {
  2531. X        clrdisp();
  2532. X
  2533. X        if (master.db_lock[0])
  2534. X        printf("Database has been locked:\n%s\n", master.db_lock);
  2535. X
  2536. X        if (!also_read_articles &&
  2537. X        unread_articles > 0 &&
  2538. X        !silent && group_name_args == 0)
  2539. X        prt_unread("There %i still %u in %g\n\n\r");
  2540. X        break;
  2541. X    }
  2542. X    gotoxy(0,Lines-1);
  2543. X    if (group_name_args == 0)
  2544. X        printf("No News\n");
  2545. X    else
  2546. X        printf("\r\n");
  2547. X    break;
  2548. X
  2549. X     case I_AM_GREP:
  2550. X    do_grep(argv+1);
  2551. X    break;
  2552. X    }
  2553. X
  2554. X    nn_exit(0);
  2555. X    /*NOTREACHED*/
  2556. X}
  2557. X
  2558. X/*
  2559. X * nn_exit() --- called whenever a program exits.
  2560. X */
  2561. X
  2562. Xnn_exit(n)
  2563. X{
  2564. X    static int loop = 0;
  2565. X
  2566. X    if (loop) exit(n);
  2567. X    loop++;
  2568. X
  2569. X    visual_off();
  2570. X
  2571. X#ifdef NNTP
  2572. X    nntp_cleanup();
  2573. X#endif /* NNTP */
  2574. X    close_master();
  2575. X    flush_newsrc();
  2576. X
  2577. X    if (who_am_i == I_AM_NN)
  2578. X    log_usage();
  2579. X
  2580. X    if (must_unlock)
  2581. X    proto_lock(I_AM_NN, PL_CLEAR);
  2582. X
  2583. X    exit(n);
  2584. X}
  2585. END_OF_FILE
  2586.   if test 17064 -ne `wc -c <'nn.c'`; then
  2587.     echo shar: \"'nn.c'\" unpacked with wrong size!
  2588.   fi
  2589.   # end of 'nn.c'
  2590. fi
  2591. echo shar: End of archive 14 \(of 22\).
  2592. cp /dev/null ark14isdone
  2593. MISSING=""
  2594. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
  2595.     if test ! -f ark${I}isdone ; then
  2596.     MISSING="${MISSING} ${I}"
  2597.     fi
  2598. done
  2599. if test "${MISSING}" = "" ; then
  2600.     echo You have unpacked all 22 archives.
  2601.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2602. else
  2603.     echo You still must unpack the following archives:
  2604.     echo "        " ${MISSING}
  2605. fi
  2606. exit 0
  2607.  
  2608. exit 0 # Just in case...
  2609.